import { Raycaster ,
  AxesHelper,
  Clock,
  Material,
  Mesh,
  PerspectiveCamera,
  Scene,
  WebGLRenderer
} from 'three'
import { OrbitControls } from 'three/examples/jsm/Addons.js'
import GUI from 'three/examples/jsm/libs/lil-gui.module.min.js'
import { onMounted, onUnmounted, ref, shallowRef } from 'vue'

export const useThree = (options = {}) => {
  const scene = shallowRef(null)
  const camera = shallowRef(null)
  const renderer = shallowRef(null)
  const controls = shallowRef(null)
  const animationId = ref(null)
  const animationCallbacks = ref([])
  const clock = new Clock()
  const gui = new GUI()
  const raycaster = new Raycaster()
  // 物理世界引用
  const world = shallowRef(null)
  const container = shallowRef(null)

  const init = () => {
    container.value = document.getElementById('webgl-container')
    const canvas = document.getElementById('webgl')

    if (!container.value) {
      console.error('Container is not defined')
      return
    }
    const { clientWidth, clientHeight } = container.value

    // Scene
    scene.value = new Scene()

    // AxesHelper
    if(options.axesHelper) {
      const axesHelper = new AxesHelper(5)
      scene.value.add(axesHelper)
    }

    // Camera
    camera.value = new PerspectiveCamera(
      75,
      clientWidth / clientHeight,
      0.1,
      1000
    )
    camera.value.position.z = 5
    scene.value.add(camera.value)

    // Controls
    controls.value = new OrbitControls(camera.value, container.value)

    // Renderer
    renderer.value = new WebGLRenderer({
      canvas,
      antialias: options.antialias ?? true,
      alpha: options.alpha ?? false
    })
    renderer.value.setSize(clientWidth, clientHeight)
    renderer.value.setPixelRatio(Math.min(window.devicePixelRatio, 2))

    clock.start()
  }

  const animate = () => {
    animationId.value = requestAnimationFrame(animate)

    const delta = clock.getDelta()
    const elapsedTime = clock.getElapsedTime()

    // 更新物理世界
    if(world.value) {
      world.value.step(1 / 60, delta, 3)
    }

    // 执行渲染前的动画回调
    animationCallbacks.value.forEach((callback) => {
      if (!callback.executeAfterRender) {
        callback(delta, elapsedTime)
      }
    })

    if (scene.value && camera.value && renderer.value) {
      controls.value?.update()
      renderer.value.render(scene.value, camera.value)
    }

    // 执行渲染后的动画回调（如后处理效果）
    animationCallbacks.value.forEach((callback) => {
      if (callback.executeAfterRender) {
        callback(delta, elapsedTime)
      }
    })
  }

  const addAnimationCallback = (callback, executeAfterRender = false) => {
    callback.executeAfterRender = executeAfterRender
    animationCallbacks.value.push(callback)
  }

  const removeAnimationCallback = (callback) => {
    const index = animationCallbacks.value.indexOf(callback)
    if (index > -1) {
      animationCallbacks.value.splice(index, 1)
    }
  }

  // 重置
  const handleResize = () => {
    if (!container.value || !renderer.value || !camera.value) return
    const { clientWidth, clientHeight } = container.value

    camera.value.aspect = clientWidth / clientHeight
    camera.value.updateProjectionMatrix()
    renderer.value.setSize(clientWidth, clientHeight)
    renderer.value.setPixelRatio(Math.min(window.devicePixelRatio, 2))
  }

  // 拾取
  const handlePick = (event) => {
    const { clientX, clientY } = event
    const { left, top } = container.value.getBoundingClientRect()

    // 将屏幕坐标转换为标准化设备坐标 (NDC, -1 到 1)
    const x = ((clientX - left) / container.value.clientWidth) * 2 - 1
    const y = -((clientY - top) / container.value.clientHeight) * 2 + 1

    raycaster.setFromCamera({ x, y }, camera.value)
    const intersects = raycaster.intersectObject(scene.value, true)

    return intersects
  }

  const dispose = () => {
    if (animationId.value) {
      cancelAnimationFrame(animationId.value)
    }
    clock.stop()

    // 销毁 GUI
    gui.destroy()

    if (renderer.value && container.value) {
      renderer.value.dispose()
    }

    scene.value?.traverse((object) => {
      if (object instanceof Mesh) {
        object.geometry.dispose()

        if (object.material instanceof Material) {
          object.material.dispose()
        } else if (Array.isArray(object.material)) {
          object.material.forEach((material) => material.dispose())
        }
      }
    })
  }

  // 初始化物理世界
  const initPhysics = (CANNON) => {
    world.value = new CANNON.World()
    world.value.gravity.set(0, -9.82, 0) // 设置重力
    world.value.broadphase = new CANNON.NaiveBroadphase() // 碰撞检测算法
    world.value.solver.iterations = 10
    return world.value
  }

  onMounted(() => {
    init()
    animate()
    window.addEventListener('resize', handleResize)
  })

  onUnmounted(() => {
    window.removeEventListener('resize', handleResize)
    dispose()
  })

  return {
    scene,
    camera,
    renderer,
    gui,
    world,
    container,
    initPhysics,
    handlePick,
    addAnimationCallback,
    removeAnimationCallback
  }
}
